视频优化(2) 与 ios 滑动bug研究

March 24, 2021

去年项目上遇到视频加载问题的时候,想到了 preload 的方式来加载视频 虽然效果不佳。只是视频的问题还有很多没有解决,这次项目里面又再次遇到视频问题,

ie 9 视频显示问题:

目前已经抛弃了低版本的 IE,至少 IE 8 是不支持得了,但是 IE 9 还是要支持的。想到我厂在全国销量,人群分布情况,win 7 + IE 9 还是有很多的,具体的浏览器分布数据一直没有拿到。在 全球范围内,IE 份额已经只有 5.34% 了,但是在国内,ie 9 的份额居然还有 9.72%,ie 11 有 7.26%,ie 8 有 5.86%,咦,原来 ie 的份额都这么多多。。。如果没有天猫以及甚至淘宝的强势推广,可能这个份额会更高。目前看来,ie 9 这两年国内的市场份额没有降低的趋势,兼容 ie 9 也是必要的了。

这里 ie 9 的 video 显示问题,指的是有些 mp4 文件可以在 ie 9 播放,有的就不能。之前处理方式都是对不能在 ie 9 播放的视频,专门替换成图片,规避问题,但是 video 标签明明是支持 ie 9 的,为何有些可以,有些不能呢?在 win 7 系统上面可以清晰的看到,支持 ie 9 播放的视频,可以看到帧宽,帧高,而不能播放的视频,则看不到,很明显 win 7 不支持这些视,所以应该是视频源的问题。

一开始以为是视频丢失帧高帧宽,通过 ffmpeg 的 scale 方式给视频一个指定高度和宽度,发现当高度高度 1088 的时候视频无法播放,而低于 1088 的时候则正常显示,这又是什么问题?由于 scale 后清晰的显示模糊,采用软件格式工厂得出的视频,指定帧宽高后,视频质量堪忧,模糊是模糊了点,但起码能用,在 video 里面采用两个标签的形式,还是可以播放的。只是具体为何 ie 9 不能播放,还是没有找到原因。

直到某天不小心发现 这篇文字,可以看到 H.264 Video Decoder,哦,原来是 win 7 平台 H.264 解码器不支持超过 1920 × 1080

[!Note] In Windows 7, the maximum supported resolution is 1920 × 1088 pixels for both software and DXVA decoding.

只要将视频的高度压缩到 1920 × 1088 就可以了。原先不能在 ie 9 播放的视频,帧高都超过了 1088。这个时候也遇到了另外一个神器 HandBrake,压缩视频非常好用,张大神的 文章有介绍到。通过反复尝试,高于超过 1920 × 1088,无法在 ie 9 播放。这是 win 7 系统的问题。甚至 ie 11 也会有这样的问题

于是合理的处理方式是有两个视频源,一个是正常的,一个是为 win 7 上面的 ie 浏览器准备的低尺寸视频。当然这会增加设计师的工作。。。。

mp4 加载的3次请求

在之前的视频优化里面,就发现视频会有三次请求,如下:

只是视频一多,发现个别视频又不会有三次网络请求。尤其是 banner 位的视频,是要秒开的(well,虽然没有人要求),三次来回的请求占据了太多时间。后来反复查找资料,发现张大神的文章 从天猫某活动视频不必要的3次请求说起。简而言之就是 mp4 文件是由一个个 box 组成的,一级嵌套一级来存放媒体信息。其中视频文件的宽高、时长、码率、编码格式等存放在 moov box 里面,如下图

mp4 box 的信息,win 10 可以通过软件 mp4info 来查看,地址: https://pan.baidu.com/s/1PcAMVaX2cc8UV3vFxpBSFQ,提取码:3ua3; 这个工具可以查看其 box 信息,如下所示:

moov 后置,如上图,则浏览器会发送三次请求,具体请求内容看张大神的解释。而 moov 前置,若没有moov.udta.meta,也可能会有三次请求(不同浏览器策略不一)。可见这个 moov 的前后置以及 moov.udta.meta 情况影响加载是否有三次请求。

至于 moov 修改,或者添加,则可以通过 ffmpeg 修改,或者简单的通过上面提到的 HandBrake,里面有 Web Optimized 可以导出优化后的视频。

视频使用心得

桌面视频播放在突破了 ie 之后,基本没有什么问题,唯一要注意的是添加 poster 来过渡好视频首帧播放。

安卓播放的问题是最多的。由于视频多为手机录像,需要有手机框配套,并且有圆角,有浮层。为了避免各式各样的问题,采用的是做个折中的弹出层播放。也采用过手机框和录像一起作为整个视频播放,但是在安卓浏览器上,原本的视频的内部圆角出现了折痕,虽然不是很明显,但是也是够奇葩的了。

HandBrake 默认的配置里面,一般没有对应的视频源尺寸,多为 1080/720/480 等尺寸,可以自己创建新的 Preset,比如采用视频源方式。

HandBrake 尺寸设置里面,要注意裁边模式,默认是自动的,但可能会出现自动模式下,裁边错误的情况,这个时候就需要手动调整了。

HandBrake 可以通过 video 选项里面 Eencoder Preset 来设置编码的速率,越慢压缩效果越好,处理后视频体积越小,但是时间开销越多。

IOS scroll 引起的bug

ios 的 safari 从 ios 5 就带有弹性滚动,而如果你要有需要在 div 里面做滚动,若只是单纯的设置 overflow-y: scroll;,页面会滚动,但是也会变得非常僵硬,卡顿。为了达到原生的效果,需要有如下设置 -webkit-overflow-scrolling: touch; 。如此可以达到原生滑动的效果。然而这个设置会带来诸多意想不到的 bug。

首先是为了配合 scroll,自然要设定一个固定高度。遇到的问题简化为如下情况:

<div class="wrapper">
  <ul class="inner">
    <li class="inner-item">
      <div class="img-wrapper">
        <img src="" alt="" /> 
      </div>
      <div class="img-wrapper">
        <img src="" alt="" /> 
      </div>      
    </li>
  </ul>
</div>

.wrapper {
  position: absolute; 
  left: 0; 
  top: 0; 
  height: 100%; 
  width: 100%; 
  overflow: auto;
}
.inner {
  overflow: scroll;
  -webkit-overflow-scrolling: touch;
}
.inner-item {}
.img-wrapper {
  position: relative;
  overflow: hidden;
  width: 100px;
  height: 100px;
}
.img {
  position: absolute;
  height: 200px;
  bottom: 0;
  left: 0;
}

-webkit-overflow-scrolling: touch; 放在 inner 类里面,是由于放在 wrapper 类里面,会经常性导致页面滑不动,触发 ios 的橡皮筋效应,而不是页面的滚动。

遇到的神奇的 bug 是:页面初始化正常,并且能够正常滚动。但是里面的 image 却会在快速滚动中出现溢出情况,而且是第二张溢出,第一张不溢出,慢慢滚动还不会出现,防不胜防。

先回顾一下溢出问题,这里的 image 由于设置了绝对定位,顾其尺寸大小,受其最近的包含块影响。image 上级元素,position: relative;,所以包含块为 img-wrapper,其是不会产生溢出效果的。那怎么这样的问题呢?难道是 -webkit-overflow-scrolling: touch; 的锅?

于是查看 apple 的官方 文档,写道:

touch Native-style scrolling. Specifying this style has the effect of creating a stacking context (like opacity, masks, and transforms).

通过设置 -webkit-overflow-scrolling: touch; 会让元素的叠层水平和 opacity, masks, and transforms 之类的一样。而值得一提的是 transforms 也可以生成包含块。难道滚动的时候,img-wrapper 这个包含块不起作用了,倒是 inner 这个包含块其作用?这么说好,好像行得通,第一张图片没有溢出,是被 inner 给设定死了溢出空间了?为了提升包含块,于是分别在 img-wrapper 与 inner-item 设定 transform: translateZ(0)。结果 设置在 inner-item 的起作用了。看来 img-wrapper 的包含块无效化了,但是这个叠层关系实在有点远,看不出所以然。只能当作是个诡异事件。

后来觉得 transform 的设置还有个妙处,针对 ios 可以起到硬件加速渲染,避免图片出不了。